﻿using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using USTF.Media.MediaService;
using System.Collections.ObjectModel;
using SUMO.MediaBrowser.Foundation;
using System.Windows.Threading;
using USTF.Media.MediaServiceConsumer.USTFMediaServiceProxy;
using System.Collections.Generic;
using USTF.Media.MediaServiceConsumer;
using SUMO.MediaBrowser.ViewModel;

namespace SUMO.MediaBrowser.ViewModel
{
    public class HierarchicalMediaItem : INotifyPropertyChanged, IEquatable<HierarchicalMediaItem>
    {
        /// <summary>
        /// Child Hierarchical Media Items of this Item
        /// </summary>
        public ObservableCollection<HierarchicalMediaItem> ChildItems = new ObservableCollection<HierarchicalMediaItem>();

        /// <summary>
        /// The current media item data
        /// </summary>
        public byte[] ItemData
        {
            set
            {
                if (_itemData == value)
                    return;
                else
                {
                    if (_itemData!=null && OriginalDataRetreived)
                    {
                        DataModified = true;
                        OriginalData = _itemData.Clone() as byte[];
                    }
                    _itemData = value;
                    OnPropertyChanged("ItemData");
                }
            }
            get
            {
                return _itemData;
            }
        }
        byte[] _itemData = null;
        
        /// <summary>
        /// Returns the original media item as byte data (if edited), or the current data if not edited
        /// </summary>
        public byte[] OriginalData
        {
            get
            {
                if (_originalData != null)
                    return _originalData;
                else if (DataModified)
                {
                    _originalData = _itemData.Clone() as byte[];
                    return _originalData;
                }
                else
                    return ItemData;
            }
            private set
            {
                if (_originalData == value)
                    return;
                _originalData = value;
                OnPropertyChanged("OriginalData");
            }
        }
        private byte[] _originalData=null;

        /// <summary>
        /// The raw data from the server for this Media Item. This object is not monitored for changes.
        /// </summary>
        public MediaItem CurrentItem
        {
            set
            {

                if (_currentItem == value)
                    return;
                else
                {
                    _currentItem = value;
                    OnPropertyChanged("CurrentItem");
                }
            }
            get
            {
                return _currentItem;
            }
        }
        MediaItem _currentItem = new MediaItem();

        /// <summary>
        /// Gets or sets a value indicating whether we need to initially attempt to asynchronously download the byte data for this media item.
        /// </summary>
        public bool FetchByteData { get; set; }
        
        /// <summary>
        /// Gets a value indicating whether the byte data for the media item has been retreived from the server
        /// </summary>
        public bool OriginalDataRetreived
        {
            get
            {
                return _originalDataRetreived;
            }
        }
        private bool _originalDataRetreived = false;

        /// <summary>
        /// Gets or sets a value indicating wether the byte data for this media item instance has been modified
        /// </summary>
        public bool DataModified
        {
            get
            {
                return _dataModified;
            }
            set
            {
                if (_dataModified == value)
                    return;
                else
                {
                    _dataModified = value;
                    OnPropertyChanged("DataModified");
                }
            }
        }
        private bool _dataModified = false;

        /// <summary>
        /// Gets or sets a property indicating whether the data for the current item is in a state of saving
        /// Data should not be modified if the value of this property is True.
        /// </summary>
        public bool IsBeingUploaded
        {
            get { return _isBeingUploaded;}
            set
            {
                if (value == _isBeingUploaded)
                    return;
                _isBeingUploaded = value;
                OnPropertyChanged("IsBeingUploaded");
            }
        }
        private bool _isBeingUploaded = false;

        /// <summary>
        /// Replaces any modifications of this media item instance's byte data with the data originally retreived from the server
        /// </summary>
        public void RevertToOriginal()
        {
            //don't do anything if either of the following is true:
            //  we don't actually have any original data (ie: it is a new item!)
            //  we actually have data!
            //  the data isn't being persisted to the server at the moment
            if (OriginalDataRetreived && _itemData != null && !IsBeingUploaded)
            {
                _itemData = OriginalData;
                DataModified = false;
                OnPropertyChanged("ItemData");
            }
        }

        /// <summary>
        /// Gets a value indicating whether child media item instances have been retreived from the server
        /// </summary>
        public bool ChildrenRetreivedFromDataSource
        {
            get
            {
                return _childrenRetreivedFromDataSource;
            }
            set
            {
                if (_childrenRetreivedFromDataSource == value)
                    return;
                _childrenRetreivedFromDataSource = value;
                OnPropertyChanged("ChildrenRetreivedFromDataSource");
            }
        }
        private bool _childrenRetreivedFromDataSource = false;

        /// <summary>
        /// Overwrites ChildItems with data from the source data service. To see the results, subscribe to the ChildItems ObservableCollection.
        /// </summary>
        public void PopulateChildrenFromDataSource()
        {
            //something has asked us to go and get child items
            //note: we should only do this once to avoid overwriting modifications
            //      it is up to the UI to ensure this does not happen (or to ask the user
            //      for confirmation).
            var client = OpsContext.Current.NewClient();

            client.GetMediaItemsCompleted +=
                (object sender, GetMediaItemsCompletedEventArgs e)
                    =>
                {
                    var mediaItems = e.Result as IEnumerable<MediaItem>;

                    e.Result.ToList().ForEach(mediaItem =>
                    {
                        ChildItems.Add(new HierarchicalMediaItem(mediaItem, true));
                    });
                    ChildrenRetreivedFromDataSource = true;

                };

            client.GetMediaItemsAsync(CurrentItem.ID);
        }


        /// <summary>
        /// Constructor. Instantiates an instance of HierarchicalMediaItem with the underlying data from the server, and an indication of whether it is worth attempting to download byte data for the media object.
        /// </summary>
        /// <param name="item"></param>
        /// <param name="fetchByteData"></param>
        public HierarchicalMediaItem(MediaItem item, bool fetchByteData)
        {
            FetchByteData = fetchByteData;
            //retreive byte data when item set is set
            this.PropertyChanged += new PropertyChangedEventHandler(HierarchicalMediaItem_PropertyChanged);

            CurrentItem = item;

            //watch for changes
            PendingModifications.Current.RegisterForChangeMonitoring(this);
            
        }

        public HierarchicalMediaItem(MediaItem item, byte[] itemData)
        {
            CurrentItem = item;
            
            //watch for changes
            PendingModifications.Current.RegisterForChangeMonitoring(this);

            ItemData = itemData;
        }

       
        #region INotifyPropertyChanged Members
         protected void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
         public event PropertyChangedEventHandler PropertyChanged;
        #endregion

         void HierarchicalMediaItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
         {
             switch (e.PropertyName)
             {
                 case "CurrentItem":
                     if (FetchByteData)
                     {
                         if (CurrentItem.MediaType == MediaType.Image)
                         {
                             var client = OpsContext.Current.NewClient();
                             client.GetDataCompleted += (object s, USTF.Media.MediaServiceConsumer.USTFMediaServiceProxy.GetDataCompletedEventArgs ev)
                                 =>
                             {
                                 ItemData = ev.Result;
                                 _originalDataRetreived = true;
                             };
                             client.GetDataAsync(CurrentItem, String.Empty);
                         }
                     }
                     break;
                 default:
                     break;
             }
         }

        

        #region IEquatable<HierarchicalMediaItem> Members

        public bool Equals(HierarchicalMediaItem other)
        {
            if (this.CurrentItem == null || other.CurrentItem == null)
                return false;

            //compare types of underlying item
            //do not compare actual data
            if (this.CurrentItem is NewMediaItem)
            {
                if (other.CurrentItem is NewMediaItem)
                {
                    return (((NewMediaItem)other.CurrentItem).Identifier.Equals(((NewMediaItem)this.CurrentItem).Identifier));
                }
                else
                {
                    return false;
                }
            }

            if (other.CurrentItem is NewMediaItem)
                return false;

            return (this.CurrentItem.ID.Equals(other.CurrentItem.ID));
        }

        #endregion
    }
}
